package weatherImporter;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

class FlexModel extends DefaultTableModel {
	
	public static final int DAY_INDEX = 0;
	public static final int MONTH_INDEX = 1;
	public static final int YEAR_INDEX = 2;
	public static final int HOUR_INDEX = 3;
	public static final int MINUTE_INDEX = 4;
	public static final int TEMPERATURE_INDEX = 5;
	public static final int HUMIDITY_INDEX = 6;
	public static final int DEWPOINT_INDEX = 7;
	public static final int BAROMETER_INDEX = 8;
	public static final int WINDSPEED_INDEX = 9;
	public static final int GUSTSPEED_INDEX = 10;
	public static final int DIRECTION_INDEX = 11;
	public static final int RAINLASTMIN_INDEX = 12;
	public static final int DAILYRAIN_INDEX = 13;
	public static final int MONTHLYRAIN_INDEX = 14;
	public static final int YEARLYRAIN_INDEX = 15;
	public static final int HEATINDEX_INDEX = 16;
	
    public FlexModel(Vector colNames) {
    	this.columnIdentifiers = colNames;
    }
    
    public Class getColumnClass(int column) {
    	switch (column) {
    		case DAY_INDEX:
    		case MONTH_INDEX:
    		case YEAR_INDEX:
    		case HOUR_INDEX:
    		case MINUTE_INDEX:	
    		case HUMIDITY_INDEX:
    		case DIRECTION_INDEX:
    			return Integer.class;
    		case TEMPERATURE_INDEX:
    		case DEWPOINT_INDEX:
    		case BAROMETER_INDEX:
    		case WINDSPEED_INDEX:
    		case GUSTSPEED_INDEX:
    		case RAINLASTMIN_INDEX:
    		case DAILYRAIN_INDEX:
    		case MONTHLYRAIN_INDEX:
    		case YEARLYRAIN_INDEX:
    		case HEATINDEX_INDEX:
    			return Float.class;
    		default:
    			return Object.class;
    	}
    }
    
    @Override
    public int getColumnCount() {
        return super.getColumnCount();
    }

    @Override
    public int getRowCount() {
        return this.getDataVector().size();
    }

    public String getColumnName(int col) {
        return (String) columnIdentifiers.elementAt(col);
    }


    /*public boolean isCellEditable(int row, int col) {
    	return false;
    }*/

    @Override
    public void setValueAt(Object aValue, int row, int column) {
    	((Vector)this.getDataVector().elementAt(row)).setElementAt(aValue, column);
    	this.fireTableCellUpdated(row, column);
    }
    
    //returns a DEEP COPY of the row at given index
    //Note: A deep copy is needed, else the original rows get altered when the new rows get altered
    public Vector getRow(int index) {
    	Object obj = null;
        try {
            // Write the object out to a byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            out.writeObject((Vector)(this.getDataVector()).elementAt(index));
            out.flush();
            out.close();

            // Make an input stream from the byte array and read
            // a copy of the object back in.
            ObjectInputStream in = new ObjectInputStream(
                new ByteArrayInputStream(bos.toByteArray()));
            obj = in.readObject();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        catch(ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
        return (Vector)obj;
    }
    
    //read csv data from a file
    public void loadFile(File file, String separator, boolean hasColNames) throws IOException {
    	BufferedReader in = new BufferedReader(new FileReader(file));
		
		String line = "";
		
		//Read first line for column names if data has column names
		if (hasColNames) {
			columnIdentifiers = new Vector();
			line = in.readLine();
			String[] values = line.split(separator);
			//int i = 0;
			for (String val : values) {
				if (!val.equals("")) {
					columnIdentifiers.add(val);
				}
			}
		}
		
		Vector input = new Vector();
		while ((line = in.readLine()) != null) {
			String[] values = line.split(separator);
			
			int i = 0;
			Vector row = new Vector();
			for (String val : values) {
				if (!val.equals("")) {
					switch (i) {
		    			case DAY_INDEX:
		    				row.add(Integer.parseInt(val));
		    				break;
		    			case MONTH_INDEX:
		    				row.add(Integer.parseInt(val));
		    				break;
		    			case YEAR_INDEX:
		    				row.add(Integer.parseInt(val));
		    				break;
		    			case HOUR_INDEX:
		    				row.add(Integer.parseInt(val));
		    				break;
		    			case MINUTE_INDEX:	
		    				row.add(Integer.parseInt(val));
		    				break;
		    			case HUMIDITY_INDEX:
		    				row.add(Integer.parseInt(val));
		    				break;
		    			case DIRECTION_INDEX:
		    				row.add(Integer.parseInt(val));
		    				break;
		    			case TEMPERATURE_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case DEWPOINT_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case BAROMETER_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case WINDSPEED_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case GUSTSPEED_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case RAINLASTMIN_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case DAILYRAIN_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case MONTHLYRAIN_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case YEARLYRAIN_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			case HEATINDEX_INDEX:
		    				row.add(Float.parseFloat(val));
		    				break;
		    			default:
		    				System.out.println("setValueAt nutzt unerkannten Index!");
		    				break;
					}
					i++;
				}
			}
			input.add(row);
		}
		this.setDataVector(input, columnIdentifiers);
		System.out.println("Done loading file! There are " + getColumnCount() + " columns and " + getRowCount() + " rows.");
		this.fireTableDataChanged();
    }
    
    public void clearTable() {
    	this.getDataVector().clear();
    	this.fireTableDataChanged();
    }
    
    //write to given file (will overwrite the given file)
    public void write(File destination, boolean withColumnNames) throws IOException {
    	DataOutputStream out = new DataOutputStream(new FileOutputStream(destination, false));
    	String SEPARATOR = ";";
    	Iterator it = this.getDataVector().iterator();
    	StringBuffer str = new StringBuffer();
    	
    	if (withColumnNames) {
    		Iterator itColNames = this.columnIdentifiers.iterator();
    		while (itColNames.hasNext()) {
    			str.append(itColNames.next()).append(SEPARATOR);
    		}
    		str.append("\n");
    		out.write(str.toString().getBytes());
    		//str = new StringBuffer();
    	}
    	   	
    	while (it.hasNext()) {
    		str.setLength(0);
    		Vector row = (Vector)it.next();
    		Iterator it2 = row.iterator();
    		while (it2.hasNext()) {
    			Object obj = it2.next();
    			if (obj instanceof Float) {
    				String val = ((Float)obj).toString();
    				val = val.replace('.', ',');
    				str.append(val).append(SEPARATOR);
    			} else {
    				str.append(obj).append(SEPARATOR);
    			}
    		}
    		str.append("\n");
    		out.write(str.toString().getBytes());
    	}
    	out.close();
    }
    
    
    public void removeColumnAndData(JTable table, int[] colIndeces) {
        Vector data = this.getDataVector();

        //Iterate over all columns which are selected for deletion
        int i = 0;
        for (int colIndex : colIndeces) {
        	Vector colIds= this.columnIdentifiers;
        	//decrease the index according to the number of already deleted columns
        	TableColumn col = table.getColumnModel().getColumn(colIndex-i);
        	int columnModelIndex = col.getModelIndex();
        	
        	colIds.remove(columnModelIndex);
        	//remove column data
        	for (int r=0; r<data.size(); r++) {
        		((Vector)this.getDataVector().elementAt(r)).removeElementAt(columnModelIndex);
        	}
        	//decrease the index of all columns after the deleted column+
        	//not needed?
        	/*Enumeration<TableColumn> enu = table.getColumnModel().getColumns();
            for (; enu.hasMoreElements(); ) {
                TableColumn c = enu.nextElement();
                if (c.getModelIndex() > columnModelIndex) {
                    c.setModelIndex(c.getModelIndex()-1);
                }
            }*/
            //set the new dataVector
            this.setDataVector(data, colIds);
            
            this.fireTableStructureChanged();
            i++;
        }
    }
    
    @Override
    public void addRow(Vector row) {
    	this.getDataVector().add(row);
    	this.fireTableRowsInserted(this.getRowCount()-1, this.getRowCount()-1);
    }
    
    @Override
    public Object getValueAt(int row, int col) {
    	return ((Vector)this.getDataVector().elementAt(row)).elementAt(col);
    }
    
}
